

using System.IO;
using System.Text;

namespace System.Net
{
    public static class WebRequestEX
    {
        public static T SetMethod<T>(this T request, string Method = "POST")
            where T : WebRequest
        {
            if(request != null && !string.IsNullOrEmpty(Method))
                request.Method = Method;
            return request;
        }

        public static T SetContentType<T>(this T request, string Content = "application/x-www-form-urlencoded")
            where T : WebRequest
        {
            if(request != null && !string.IsNullOrEmpty(Content))
                request.ContentType = Content;
            return request;
        }

        public static T SetAcceptTypes<T>(this T request, params string[] types)
            where T : WebRequest
        {
            if(request != null && types != null && types.Length != 0)
                request.ContentType = types.ToSeparatedStr(",");
            return request;
        }

        public static HttpWebRequest SetUserAgent(this HttpWebRequest request,
                    string UserAgent = "Mozilla/5.0 (Windows NT 6.1; rv:18.0) Gecko/20100101 Firefox/18.0")
        {
            if(request != null)
                request.UserAgent = UserAgent;
            return request;
        }

        public static T SetAcceptLanguage<T>(this T request, string Languages = "ru-RU,ru;q=0.8,en-US;q=0.5,en;q=0.3")
            where T : WebRequest
        {
            if(request != null)
                request.Headers.Add(HttpRequestHeader.AcceptLanguage, Languages);
            return request;
        }

        public static T SetEncoding<T>(this T request, string Encoding = "gzip, deflate")
            where T : WebRequest
        {
            if(request != null)
                request.Headers.Add(HttpRequestHeader.AcceptEncoding, Encoding);
            return request;
        }

        public static HttpWebRequest SetAutomaticDecompression(this HttpWebRequest request,
                    DecompressionMethods Decompression = DecompressionMethods.Deflate | DecompressionMethods.GZip)
        {
            if(request != null)
                request.AutomaticDecompression = Decompression;
            return request;
        }

        public static HttpWebRequest InitializeCoociesContainer(this HttpWebRequest request)
        {
            CookieContainer Cookies = null;
            return InitializeCoociesContainer(request, ref Cookies);
        }

        public static HttpWebRequest InitializeCoociesContainer(this HttpWebRequest request,
                    ref CookieContainer Cookies)
        {
            Cookies = null;
            if(request != null)
            {
                if(Cookies == null)
                    Cookies = new CookieContainer();
                request.CookieContainer = Cookies;
            }
            return request;
        }

        public static HttpWebRequest SetReferer(this HttpWebRequest request, string Referer = null)
        {
            if(request != null)
                request.Referer = Referer;
            return request;
        }

        public static Stream Send(this WebRequest request, string Str, out HttpStatusCode Status)
        {
            return request.Send(Str, Encoding.Default, out Status);
        }

        public static Stream Send(this WebRequest request, string Str, Encoding encoding, out HttpStatusCode Status)
        {
            return request.Send(encoding.GetBytes(Str), out Status);
        }

        public static Stream Send(this WebRequest request, byte[] Data, out HttpStatusCode Status)
        {
            if(request == null)
                throw new ArgumentNullException(nameof(request));
            if(Data == null)
                throw new ArgumentNullException(nameof(Data));
            request.ContentLength = Data.Length;
            request.GetRequestStream().Using(s => s.Write(Data, 0, Data.Length));
            var response = (HttpWebResponse)request.GetResponse();
            return (Status = response.StatusCode) != HttpStatusCode.OK ? null : response.GetResponseStream();
        }

        public static Stream Send(this WebRequest request, string Str, out HttpWebResponse Response)
        {
            return request.Send(Str, Encoding.Default, out Response);
        }

        public static Stream Send(this WebRequest request, string Str, Encoding encoding, out HttpWebResponse Response)
        {
            return request.Send(encoding.GetBytes(Str), out Response);
        }

        public static Stream Send(this WebRequest request, byte[] Data, out HttpWebResponse Response)
        {
            if(request == null)
                throw new ArgumentNullException(nameof(request));
            if(Data == null)
                throw new ArgumentNullException(nameof(Data));
            request.ContentLength = Data.Length;
            request.GetRequestStream().Using(s => s.Write(Data, 0, Data.Length));
            Response = (HttpWebResponse)request.GetResponse();
            return Response.StatusCode != HttpStatusCode.OK ? null : Response.GetResponseStream();
        }

        public static IAsyncResult BeginSend(this WebRequest request, string Str, AsyncCallback OnResponse)
        {
            return request.BeginSend(Str, Encoding.Default, OnResponse);
        }

        public static IAsyncResult BeginSend(this WebRequest request, string Str, Encoding encoding, AsyncCallback OnResponse)
        {
            return request.BeginSend(encoding.GetBytes(Str), OnResponse);
        }

        public static IAsyncResult BeginSend(this WebRequest request, byte[] Data, AsyncCallback OnResponse)
        {
            if(request == null)
                throw new ArgumentNullException(nameof(request));
            if(Data == null)
                throw new ArgumentNullException(nameof(Data));
            request.ContentLength = Data.Length;
            request.GetRequestStream().Using(s => s.Write(Data, 0, Data.Length));
            return request.BeginGetResponse(OnResponse, request);
        }

        public static AsyncCallback GetSendResponse(this WebRequest request, Action<HttpWebResponse> OnResponse)
        {
            return aResult => OnResponse((HttpWebResponse)((WebRequest)aResult.AsyncState).EndGetResponse(aResult));
        }

        public static AsyncCallback GetSendResponse(this WebRequest request, Action<Stream> OnResponse)
        {
            return aResult =>
            {
                var response = (HttpWebResponse)((WebRequest)aResult.AsyncState).EndGetResponse(aResult);
                if(response.StatusCode == HttpStatusCode.OK)
                    OnResponse(response.GetResponseStream());
            };
        }
    }
}